package com.sunda.spmsoversea.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmsoversea.constant.CommonConstant;
import com.sunda.spmsoversea.dto.OverseaInvCheckActionSearchDTO;
import com.sunda.spmsoversea.entity.OverseaInvCheck;
import com.sunda.spmsoversea.entity.OverseaInvCheckAction;
import com.sunda.spmsoversea.entity.OverseaInvCheckActionDtl;
import com.sunda.spmsoversea.entity.WhsStorageInventory;
import com.sunda.spmsoversea.mapper.OverseaInvCheckActionMapper;
import com.sunda.spmsoversea.mapper.OverseaInvCheckMapper;
import com.sunda.spmsoversea.service.IOverseaInvCheckActionDtlService;
import com.sunda.spmsoversea.service.IOverseaInvCheckActionService;
import com.sunda.spmsoversea.service.IOverseaOperateLogService;
import com.sunda.spmsoversea.service.IWhsStorageInventoryService;
import com.sunda.spmsuser.entity.SpmsUser;
import localhost.services.ExtHrmresources.ExtHrmresourcesPortTypeProxy;
import localhost.services.RequestService.RequestServicePortTypeProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import weaver.soa.workflow.request.*;

import java.rmi.RemoteException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.sunda.spmscommon.Constans.*;
import static com.sunda.spmscommon.constant.OaConstant.BUSINESS_TYPE_INV_CHECK;
import static com.sunda.spmsoversea.constant.CommonConstant.INVALID_DATE;
import static com.sunda.spmsoversea.constant.CommonConstant.oaLog;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.ADD;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.SUB;

/**
 * <p>
 * 仓库盘盈盘亏 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-05-10
 */
@Service
public class OverseaInvCheckActionServiceImpl extends ServiceImpl<OverseaInvCheckActionMapper, OverseaInvCheckAction>
        implements IOverseaInvCheckActionService {

    @Autowired
    IOverseaInvCheckActionDtlService iOverseaInvCheckActionDtlService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Value("${oa.workflow.id3168}")
    String workflow3168;

    @Autowired OverseaInvCheckMapper overseaInvCheckMapper;

    @Override
    public List<OverseaInvCheckAction> getInvChkAcByInvChkId(String invChkId) {
        return this.baseMapper.selectList(new QueryWrapper<OverseaInvCheckAction>().eq("INVENTORY_CHECK_ID", invChkId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult getInvCheckAcWithDtl(String uuid) {
        try {
            QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                    uuid);
            OverseaInvCheckAction inventoryCheckAction = this.baseMapper.selectOne(queryWrapper);
            if (null == inventoryCheckAction) {
                throw new Exception("Could not find Inventory Check Action for uuid: " + uuid);
            }

            ResponseResult res = iOverseaInvCheckActionDtlService.getInvCheckAcDtl(uuid);
            if (res.getCode() != 200) {
                throw new Exception(res.getMsg());
            }

            return res.add("invCheckAc", inventoryCheckAction);

        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error(e.getMessage());
        }
    }

    /**
     * 获取库存盘点任务列表 { "werks":["CN01","CM31"], "whsLocationCode":["1011","1061"],
     * "inventoryCheckCategory":"1", //盘点类别 1-日常盘点 2-月度盘点 3-动态盘点 4-其它盘点
     * "createDate":["20210401","20210501"], "inventoryCheckId":"CN01-20210511-INV",
     * "spmsStatus":"1", 任务状态：1-草稿;2-提交OA成功；3-提交OA失败；4-OA审批不通过；5-OA审批通过待上传SAP;
     * 6-上传SAP失败 7 -上传SAP成功 8 - 已撤销
     */
    @Override
    public ResponseResult getInvCheckAcList(JSONObject InvCheckFilter) {
        List<String> werks = InvCheckFilter.containsKey("werks") ? (List) InvCheckFilter.getJSONArray("werks") : null;
        List<String> whsLocationCode = InvCheckFilter.containsKey("whsLocationCode")
                ? (List) InvCheckFilter.getJSONArray("whsLocationCode")
                : null;
        String inventoryCheckCategory = InvCheckFilter.containsKey("inventoryCheckCategory")
                ? InvCheckFilter.getString("inventoryCheckCategory")
                : null;
        String spmsStatus = InvCheckFilter.containsKey("spmsStatus") ? InvCheckFilter.getString("spmsStatus") : null;
        String inventoryCheckId = InvCheckFilter.containsKey("inventoryCheckId")
                ? InvCheckFilter.getString("inventoryCheckId")
                : null;
        String spmsId = InvCheckFilter.containsKey("spmsId") ? InvCheckFilter.getString("spmsId") : null;
        String startDate = null, endDate = null;
        if (InvCheckFilter.containsKey("createDate")) {
            List<String> datePeriod = (List) InvCheckFilter.getJSONArray("createDate");
            if (datePeriod.size() == 2) {
                startDate = datePeriod.get(0);
                endDate = datePeriod.get(1);
            }
        }
        QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>();
        if (null != werks && werks.size() > 0) {
            queryWrapper.in("WERKS", werks);
        }
        if (null != whsLocationCode && whsLocationCode.size() > 0) {
            queryWrapper.in("WHS_LOCATION_CODE", whsLocationCode);
        }

        if (StringUtils.isNotEmpty(inventoryCheckCategory)) {
            queryWrapper.eq("INVENTORY_CHECK_CATEGORY", inventoryCheckCategory);
        }
        if (StringUtils.isNotEmpty(inventoryCheckId)) {
            queryWrapper.eq("INVENTORY_CHECK_ID", inventoryCheckId);
        }
        if (StringUtils.isNotEmpty(spmsId)) {
            queryWrapper.eq("SPMS_ID", spmsId);
        }
        if (StringUtils.isNotEmpty(spmsStatus)) {
            queryWrapper.eq("SPMS_STATUS", spmsStatus);
        }
        if (StringUtils.isNotEmpty(startDate)) {
            queryWrapper.between("CREATE_DATE", startDate, endDate);
        }
        try {
            return ResponseResult.success().add("invCheckAcList",
                    this.baseMapper.selectList(queryWrapper.orderByDesc("CREATE_TIME")));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("Failed when query Inventory Check Action");
        }
    }

    /**
     * 新建盘盈亏单据 1. 有uuid 更新 2. 无uuid 新建
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateInvCheckAc(JSONObject InvCheckDoc, String userId) {
        try {
            JSONObject invCheckAc = InvCheckDoc.containsKey("invCheckAc") ? InvCheckDoc.getJSONObject("invCheckAc")
                    : null;
            JSONArray invCheckAcDtls = InvCheckDoc.containsKey("invCheckAcDtls")
                    ? InvCheckDoc.getJSONArray("invCheckAcDtls")
                    : null;
            if (null == invCheckAc || null == invCheckAcDtls) {
                throw new Exception(
                        "Error, invCheckAc or invCheckAcDtls missed from the parameters, please double check");
            }
            OverseaInvCheckAction inventoryCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
            if (StringUtils.isNotEmpty(inventoryCheckAction.getUuid())) {
                ResponseResult checkStatusValidateResp = checkStatusValidate(invCheckAc);
                if (200 != checkStatusValidateResp.getCode()) {
                    return checkStatusValidateResp;
                }
                // 更新
                QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                        inventoryCheckAction.getUuid());
                ResponseResult res = iOverseaInvCheckActionDtlService.updateInvCheckDtl(inventoryCheckAction.getUuid(),
                        invCheckAcDtls);
                if (res.getCode() == 200) {
                    this.baseMapper.update(inventoryCheckAction, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, inventoryCheckAction.getUuid(),
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_UPDATE
                                    : INV_CHECK_ACTION_PK_UPDATE,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvCheck Profit Update"
                                    : "InvCheck Loss Update",
                            "1");
                    return res.add("invCheckAc", this.baseMapper.selectOne(queryWrapper));
                }
                throw new Exception(res.getMsg());
            } else {
                // 新建
                String uuid = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
                inventoryCheckAction.setUuid(uuid);
                ResponseResult res = iOverseaInvCheckActionDtlService.updateInvCheckDtl(uuid, invCheckAcDtls);
                if (res.getCode() == 200) {
                    this.baseMapper.insert(inventoryCheckAction);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_UPDATE
                                    : INV_CHECK_ACTION_PK_UPDATE,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvCheck Profit Initial"
                                    : "InvCheck Loss Initial",
                            "1");
                    QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>()
                            .eq("UUID", uuid);
                    return res.add("invCheckAc", this.baseMapper.selectOne(queryWrapper));
                }
                throw new Exception(res.getMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /** 更新之前检验当前数据状态是否和 currentStatus 一致，不一致要防止重复提交导致的更新操作 */
    ResponseResult checkStatusValidate(JSONObject invCheckAc) {
        try {
            String uuid = invCheckAc.getString("uuid");
            String currentStatus = invCheckAc.getString("currentStatus");
            if (StringUtils.isEmpty(uuid) || StringUtils.isEmpty(currentStatus)) {
                return ResponseResult.error().add("error", "更新单据uuid 或 currentStatus不能为空");
            }
            OverseaInvCheckAction checkAction = this.baseMapper
                    .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
            if (checkAction == null || !currentStatus.equals(checkAction.getSpmsStatus())) {
                return ResponseResult.error().add("error", "单据状态已更新请刷新后重试");
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /**
     * 根据任务uuid，获取盘盈盘亏结果提交SAP；状态为 5OA审批通过，6提交SAP失败 才能被提交，其余状态返回错误信息。 1.先检查数据是否都可操作；
     * 2.计算仓库库存，计算储位库存，记录仓库库存、储位库存操作日志； 3.提交SAP成功，更新单据状态为
     * 4提交SAP成功，记录返回信息，记录日志；提交SAP失败，更新状态为6提交SAP失败，记录日志； 4.重新提交SAP时，不执行库存计算过程。
     * 任务状态：1-草稿;2-提交OA成功；3-提交OA失败；4-OA审批不通过；5-OA审批通过待上传SAP; 6-上传SAP失败 7 -上传SAP成功 8
     * - 已撤销
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult getInventoryCheckActionToSap(String uuid, String postingDate, String userId,
            String remarks, String currentStatus) {
        if (StringUtils.isEmpty(postingDate) || StringUtils.isEmpty(uuid)) {
            return ResponseResult.error().add("error", "请求参数错误请重试");
        }
        if (StringUtils.isEmpty(remarks)) {
            remarks = "";
        }
        OverseaInvCheckAction inventoryCheckAction = this.baseMapper
                .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
        if (inventoryCheckAction == null) {
            return ResponseResult.error().add("error", "此盘盈盘亏单据不存在");
        }
        if (!currentStatus.equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "单据状态已更新请刷新后重试");
        }
        if (!"5".equals(inventoryCheckAction.getSpmsStatus()) && !"6".equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "此状态禁止提交SAP");
        }
        Map<String, Object> Head = formatHeadData(inventoryCheckAction, postingDate);
        List<Map<String, Object>> Items = new ArrayList<>();

        Items = formatItemsDataM(uuid);

        if (Head == null || Items.size() == 0) {
            return ResponseResult.error();
        }
        /**
         * 合规数据提交SAP，先更新SPMS仓库库存、储位库存，更新成功后再提交SAP；更新失败返回错误信息。
         * 4-提交SAP成功，获取提交返回结果；6-提交SAP失败；
         */
        try {
            /** 首次提交SAP时计算库存；提交SAP失败单据重新提交SAP忽略库存计算。 */
            if ("5".equals(inventoryCheckAction.getSpmsStatus())) {
                ResponseResult updateInventoryResult = updateInventory(inventoryCheckAction, uuid, userId);
                if (updateInventoryResult.getCode() != 200) {
                    throw new Exception("库存更新过程出错");
                    // return updateInventoryResult;
                }
            }
            JSONObject dataToSap = formatDataToSap(Head, Items);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon((dataToSap)));

            if (message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").containsKey("O_TYPE")
                    && "S".equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_TYPE"))) {

                String O_MBLNR = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_MBLNR")
                        .trim();
                String O_MJAHR = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_MJAHR")
                        .trim();
                this.baseMapper.updateInventoryCheckActionStatus(uuid, "7", O_MBLNR, O_MJAHR, postingDate, remarks);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                        "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_SAP
                                : INV_CHECK_ACTION_PK_SAP,
                        "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvChk Profit SAP success"
                                : "InvChk Loss SAP Success",
                        "2", dataToSap.toJSONString(), message.toJSONString(), "盘点任务提交SAP");
                return ResponseResult.success().add("sapReturnedMessage", message)
                        .add("invCheckAc",
                                this.baseMapper.selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid)))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid))
                        .add("dataToSap", dataToSap);
            }
            this.baseMapper.updateInventoryCheckActionStatus(uuid, "6", "", "", postingDate, remarks);
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                    "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_SAP_ERROR
                            : INV_CHECK_ACTION_PK_SAP_ERROR,
                    "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvChk Profit SAP Failure"
                            : "InvChk Loss SAP Falure",
                    "2", dataToSap.toJSONString(), message.toJSONString(), "盘点任务提交SAP");
            return ResponseResult.error().add("sapReturnedMessage", message).add("dataToSap", dataToSap);

        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("请求ESB出错");
        }
    }

    /**
     * 701 盘盈，计算备件货仓库库存、储位库存；计算贸易货储位库存； 702 盘亏，计算备件货仓库库存、储位库存；计算贸易货储位库存；
     * 
     * @param inventoryCheckAction
     * @param uuid
     * @return
     */
    ResponseResult updateInventory(OverseaInvCheckAction inventoryCheckAction, String uuid, String userId) {
        try {
            String moveType = inventoryCheckAction.getInventoryActionType();
            String operateType = moveType.equals("701") ? ADD : SUB;
            List<Map<String, Object>> inventoryDtl = this.baseMapper.getInventoryCheckActionAndDtl(uuid);
            ResponseResult checkResult = checkDataValidate(inventoryCheckAction, inventoryDtl);
            if (checkResult.getCode() != 200) {
                return checkResult;
            }
            for (int i = 0; i < inventoryDtl.size(); i++) {
                String materialNo = inventoryDtl.get(i).get("materialNo") == null ? null
                        : inventoryDtl.get(i).get("materialNo").toString();
                double discrepancy = Math.abs(Double.parseDouble(inventoryDtl.get(i).get("discrepancy").toString()));
                String storageUuid = inventoryDtl.get(i).get("storageUuid").toString();
                ResponseResult result = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo,
                        discrepancy, operateType);
                if (result.getCode() != 200) {
                    return result;
                }
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error();
        }
    }

    ResponseResult checkDataValidate(OverseaInvCheckAction inventoryCheckAction,
            List<Map<String, Object>> inventoryDtl) {
        try {
            /** 701-盘盈加库存，可忽略判断；702-盘亏需要扣减库存，需检查对应库存是否够扣减。 */
            if ("702".equals(inventoryCheckAction.getInventoryActionType())) {
                if (inventoryDtl == null || inventoryDtl.size() == 0) {
                    return ResponseResult.error("请求盘盈盘亏结果查询不存在");
                }
                for (int i = 0; i < inventoryDtl.size(); i++) {
                    String storageUuid = inventoryDtl.get(i).get("storageUuid").toString();
                    if (storageUuid == null) {
                        return ResponseResult.error("盘点结果信息对应储位信息不能为空");
                    }
                    double discrepancy = Double.parseDouble(inventoryDtl.get(i).get("discrepancy").toString());
                    String materialNo = inventoryDtl.get(i).get("materialNo").toString();
                    WhsStorageInventory materialOnStorage = iWhsStorageInventoryService
                            .getWhsStorageInventory(storageUuid, materialNo);
                    if (materialOnStorage == null || discrepancy > materialOnStorage.getAvailableQty()) {
                        return ResponseResult.error(materialNo + " 盘亏数量大于对应储位库存数量，请检查数据后重试");
                    }
                }
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("库存校验出错");
        }
    }

    JSONObject formatDataToSap(Map<String, Object> Head, List<Map<String, Object>> Items) {
        JSONObject object = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject REQUEST = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("Items", Items);
        REQUEST_DATA.put("Operation", "Z_SPMS_SKU_CHECK");
        REQUEST_DATA.put("Type", "SKU_CHECK");

        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        object.put("REQUEST", REQUEST);
        return object;
    }

    Map<String, Object> formatHeadData(OverseaInvCheckAction inventoryCheckAction, String postingDate) {
        Map<String, Object> map = new HashMap<>();
        map.put("bldat", inventoryCheckAction.getCreateDate().replaceAll("-", ""));
        map.put("budat", postingDate.replaceAll("-", ""));
        map.put("bwart", inventoryCheckAction.getInventoryActionType());
        map.put("werks", inventoryCheckAction.getWerks());
        map.put("lgort", inventoryCheckAction.getWhsLocationCode());
        map.put("bktxt", inventoryCheckAction.getVoucherText() == null ? "" : inventoryCheckAction.getVoucherText());
        return map;
    }

    List<Map<String, Object>> formatItemsDataM(String uuid) {
        try {
            List<Map<String, Object>> checkActionDtlList = iOverseaInvCheckActionDtlService.getInventoryActionDtl(uuid);
            if (checkActionDtlList.size() == 0) {
                return null;
            }
            List<Map<String, Object>> mapList = new ArrayList<>();
            for (Map<String, Object> obj : checkActionDtlList) {
                Map<String, Object> map = new HashMap<>();
                map.put("zeile", obj.get("taskRowId").toString());
                map.put("matnr", obj.get("materialNo").toString());
                map.put("menge", obj.get("discrepancy").toString());
                map.put("meins", obj.get("basicUnit").toString());
                map.put("lifnr", obj.get("relateAccount") == null ? "" : obj.get("relateAccount").toString());
                map.put("kostl", obj.get("costCenter") == null ? "" : obj.get("costCenter").toString());
                map.put("sgtxt", obj.get("voucherItemText") == null ? "" : obj.get("voucherItemText").toString());
                map.put("werks", obj.get("werks").toString());
                map.put("lgort", obj.get("whsLocationCode").toString());
                mapList.add(map);
            }
            return mapList;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public List<Map<String, Object>> getICALogs(String uuid) {
        return iOverseaOperateLogService.getByDocumentNumber(uuid);
    }

     /** 检查并关闭盘点单 */
    public ResponseResult checkAndCloseInvChk(String inventoryCheckId) {
        OverseaInvCheck inventoryCheck=overseaInvCheckMapper.selectOne(new QueryWrapper<OverseaInvCheck>().eq("INVENTORY_CHECK_ID",inventoryCheckId));
        if(null==inventoryCheck){
            return ResponseResult.error("The give invcheck id is not exist: " + inventoryCheckId);
        }
        List<OverseaInvCheckAction> inventoryCheckActions=getInvChkAcByInvChkId(inventoryCheckId);
        boolean isCoseable=true;
        if(null!=inventoryCheckActions && inventoryCheckActions.size()>0){
            for(int i=0;i<inventoryCheckActions.size();i++){
                if(!inventoryCheckActions.get(i).getSpmsStatus().equals("7")){
                    isCoseable=false;
                }
            }
        }

        if(isCoseable){
            inventoryCheck.setSpmsStatus("5");
            overseaInvCheckMapper.update(inventoryCheck,new QueryWrapper<OverseaInvCheck>().eq("INVENTORY_CHECK_ID",inventoryCheckId));
        }

        return ResponseResult.success().add("inventoryCheck",inventoryCheck);
    }

    @Override
    public ResponseResult updateOverseaInvChkAcByOa(String userId, String oaBianhao, String oaStatus) {
        if (StringUtils.isEmpty(oaBianhao) || StringUtils.isEmpty(oaStatus)) {
            return ResponseResult.error("OA Bianmao is empty");
        }

        try {
            OverseaInvCheckAction overseaInvChkAc = this.baseMapper
                    .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("OA_BIANHAO", oaBianhao));
            if (overseaInvChkAc == null) {
                return ResponseResult.error("failed to select Oversea Inv Chk Ac by OA Bianhao:" + oaBianhao);
            }
            if (!"2".equals(overseaInvChkAc.getSpmsStatus())) {
                return ResponseResult.error("状态禁止OA回写: spmsStatus:" + overseaInvChkAc.getSpmsStatus());
            }
            if ("S".equals(oaStatus)) {
                // OA 审批通过,更新状态
                OverseaInvCheckAction ovAc = new OverseaInvCheckAction();
                ovAc.setSpmsStatus("5");
                ovAc.setUuid(overseaInvChkAc.getUuid());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String oaApprovalDate = sdf.format(new Date());
                ovAc.setOaApprovalDate(oaApprovalDate);
                this.baseMapper.update(ovAc,
                        new UpdateWrapper<OverseaInvCheckAction>().eq("UUID", overseaInvChkAc.getUuid()));
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaInvChkAc.getUuid(), "OA审批通过",
                        "OA Approved", "1", "", "", "盘点任务OA审批");
                // 提交SAP
                try {
                    ResponseResult submitSapResult = getInventoryCheckActionToSap(overseaInvChkAc.getUuid(),
                            overseaInvChkAc.getPostingDate(), userId, overseaInvChkAc.getRemarks(), "5");
                    if (SUCCESS.equals(submitSapResult.getCode())) {
                        /** 检查并关闭盘点单 */
                        ResponseResult invChkRes = checkAndCloseInvChk(overseaInvChkAc.getInventoryCheckId());
                        if (invChkRes.getCode() == 200) {
                            return ResponseResult.success("SPMS更新成功，结果提交SAP成功");
                        }else{
                            return ResponseResult.success("揭交SAP成功,更新上游盘点单据失败");
                        }
                    } else {
                        return ResponseResult.success("SPMS更新成功，结果提交SAP失败");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return ResponseResult.success("SPMS更新成功，结果提交SAP失败");
                }
            } else {
                // OA 审批退回,更新状态
                OverseaInvCheckAction ovAc = new OverseaInvCheckAction();
                ovAc.setSpmsStatus("4");
                ovAc.setUuid(overseaInvChkAc.getUuid());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String oaApprovalDate = sdf.format(new Date());
                ovAc.setOaApprovalDate(oaApprovalDate);
                this.baseMapper.update(ovAc,
                        new UpdateWrapper<OverseaInvCheckAction>().eq("UUID", overseaInvChkAc.getUuid()));
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaInvChkAc.getUuid(), "OA审批退回",
                        "OA Rejected", "1", "", "", "盘点任务OA审批");
                return ResponseResult.success();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error(e.getMessage());
        }
    }

    /**
     * 盘盈盘亏提交OA 1.拼接提交OA信息，
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult overseaInvChkAcToOa(JSONObject invCheckAc, SpmsUser spmsUser,
            JSONArray invCheckAcDtls) {
        try {
            String uuid = invCheckAc.getString("uuid");
            QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                    uuid);
            OverseaInvCheckAction overseaInvChkAc = this.baseMapper.selectOne(queryWrapper);
            if (overseaInvChkAc == null) {
                return ResponseResult.error("请求盘盈亏单不存在");
            }
            // 将前端传入的参数合并入overseaInvChkAc
            overseaInvChkAc.setSubmitOaDate(invCheckAc.getString("submitOaDate"));
            overseaInvChkAc.setRemarks(invCheckAc.getString("remarks"));
            overseaInvChkAc.setPostingDate(invCheckAc.getString("postingDate"));
            // 检查是否可以提交OA
            ResponseResult checkDataToOa = checkDataToOa(overseaInvChkAc);
            if (checkDataToOa.getCode() != CommonConstant.SUCCESS) {
                return checkDataToOa;
            }

            // 更新行明细上的remarks
            ResponseResult dtlUpdateRes = iOverseaInvCheckActionDtlService.updateInvCheckDtl(uuid, invCheckAcDtls);
            if (dtlUpdateRes.getCode() != 200) {
                return dtlUpdateRes;
            }

            // SPMS生成OA单据号参考：3168-2021-11-001，提交成功需存入 OA_FIELD 字段中；
            // String oaOrderNo = generateOaOrderNo(overseaInvChkAc.getSubmitOaDate());
            // 提交OA
            int dnDataToOaResult = dnDataToOa(overseaInvChkAc, spmsUser);

            if (dnDataToOaResult > 0) {
                // TODO 提交成功，更新交货单状态，OA单据号，编号字段更新，记录提交日志；
                invCheckAc.put("spmsStatus", "2");
                invCheckAc.put("oaWorkflow", "3168");
                invCheckAc.put("oaBianhao", String.valueOf(dnDataToOaResult));
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);
                return ResponseResult.success()
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            } else if (dnDataToOaResult == -2) {
                // 提交失败
                invCheckAc.put("spmsStatus", "3");
                invCheckAc.put("oaWorkflow", "3168");
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);
                return ResponseResult.error("-2 用户没有流程创建权限，盘盈盘亏提交OA审批失败")
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            } else {
                invCheckAc.put("spmsStatus", "3");
                invCheckAc.put("oaWorkflow", "3168");
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);

                return ResponseResult.error("盘盈盘亏提交OA审批失败")
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            }
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    String generateOaOrderNo(String submitOaDate) {
        String currentNo = this.baseMapper.getOaOrderNo(submitOaDate);
        String tempStr = "00" + (Integer.parseInt(currentNo) + 1);
        String nextNo = tempStr.substring(tempStr.length() - 3);
        return "3168-" + submitOaDate.substring(0, 7) + nextNo;
    }

    ResponseResult checkDataToOa(OverseaInvCheckAction overseaInvChkAc) {
        String submitOaDate = overseaInvChkAc.getSubmitOaDate();
        if (StringUtils.isEmpty(submitOaDate)) {
            return ResponseResult.error("请求提交OA日期不能为空");
        }
        String postingDate = overseaInvChkAc.getPostingDate();
        if (StringUtils.isEmpty(postingDate)) {
            return ResponseResult.error("SAP过账日期不能为空");
        }
        if (INVALID_DATE.equals(submitOaDate)) {
            return ResponseResult.error("提交OA日期格式错误请重试");
        }
        if (INVALID_DATE.equals(postingDate)) {
            return ResponseResult.error("SAP过账日期格式错误请重试");
        }
        String spmsStatus = overseaInvChkAc.getSpmsStatus();
        if (!"1".equals(spmsStatus) && !"3".equals(spmsStatus) && !"4".equals(spmsStatus)) {
            return ResponseResult.error("当前状态不可提交OA");
        }

        List<OverseaInvCheckActionDtl> dtlList = iOverseaInvCheckActionDtlService
                .getICADList(overseaInvChkAc.getUuid());
        if (dtlList.size() <= 0) {
            return ResponseResult.error("盘盈亏任务没有行项");
        }
        return ResponseResult.success();
    }

    /**
     * 新流程的requestid 如果小于等于0表示失败 -1：创建流程失败 -2：用户没有流程创建权限 -3：创建流程基本信息失败 -4：保存表单主表信息失败
     * -5：更新紧急程度失败 -6：流程操作者失败 -7：流转至下一节点失败 -8：节点附加操作失败
     * 
     * @param overseaInvChkAc
     * @param spmsUser
     * @return
     */
    int dnDataToOa(OverseaInvCheckAction overseaInvChkAc, SpmsUser spmsUser) {

        List<Map<String, Object>> dtlList = iOverseaInvCheckActionDtlService
                .getOverseaInvChkDtls(overseaInvChkAc.getUuid());
        ExtHrmresourcesPortTypeProxy proxy = new ExtHrmresourcesPortTypeProxy();
        RequestServicePortTypeProxy wfproxy = new RequestServicePortTypeProxy();
        try {
            RequestInfo reqinfo = new RequestInfo();
            reqinfo.setCreatorid(spmsUser.getWorkId()); // OAID 提交人
            reqinfo.setWorkflowid(workflow3168);// workflowid 为测试系统ID
            reqinfo.setRequestlevel("0");// 紧急程度 默认
            reqinfo.setRemindtype("0"); // 默认
            reqinfo.setIsNextFlow("1"); // 默认
            reqinfo.setDescription("海外备件仓盘盈盘亏结果审批 SPMS单号:" + overseaInvChkAc.getSpmsId()); // 自定义

            Map<String, Object> mapHead = new HashMap<>();
            mapHead.put("bianhao", "");
            mapHead.put("workcode", spmsUser.getUserId());
            mapHead.put("workflowdate", overseaInvChkAc.getSubmitOaDate());
            mapHead.put("requestuserid", spmsUser.getWorkId());
            mapHead.put("dep", spmsUser.getDeptId() == null ? "" : spmsUser.getDeptId());
            mapHead.put("jobtitle", spmsUser.getPositionId() == null ? "" : spmsUser.getPositionId());
            mapHead.put("sub", spmsUser.getCompany() == null ? "" : spmsUser.getCompany());
            mapHead.put("fendian", spmsUser.getBranchPoint() == null ? "" : spmsUser.getBranchPoint());
            mapHead.put("joblevel", "");
            mapHead.put("area", "");
            mapHead.put("tzremark", "调账说明");
            mapHead.put("additional", "1");
            mapHead.put("Executivepersonnel", spmsUser.getWorkId());
            mapHead.put("posdh", overseaInvChkAc.getSpmsId());
            mapHead.put("spmsordernum", overseaInvChkAc.getSpmsId());
            mapHead.put("businessType", BUSINESS_TYPE_INV_CHECK);

            MainTableInfo wmi = new MainTableInfo();
            Property[] wrti = new Property[mapHead.size()];
            int i = 0;
            for (Map.Entry<String, Object> entry : mapHead.entrySet()) {
                wrti[i] = new Property();
                wrti[i].setName(entry.getKey());
                wrti[i].setValue(entry.getValue().toString());
                i++;
            }
            wmi.setProperty(wrti);

            List<Map<String, Object>> mapList = new ArrayList<>();
            for (int j = 0; j < dtlList.size(); j++) {
                Map<String, Object> itemDTO = dtlList.get(j);
                double discrepancy = Double.parseDouble(itemDTO.get("discrepancy").toString());
                Map<String, Object> map = new HashMap<>();
                map.put("xh", String.valueOf(j));
                map.put("wlid", itemDTO.get("materialNo"));
                map.put("wltext", itemDTO.get("materialZhDesc"));
                map.put("wlunit", itemDTO.get("basicUnit"));

                /** 盘盈 则按出库类型 10 */
                if (discrepancy > 0) {
                    map.put("wlquantity", Math.abs(discrepancy));
                    map.put("stocktype", 10);
                }
                /** 盘亏 则按出库类型 12 */
                if (discrepancy < 0) {
                    map.put("wlquantity", Math.abs(discrepancy));
                    map.put("stocktype", 12);
                }
                map.put("area", "");
                map.put("colorno", "");
                map.put("causeofbroken", itemDTO.get("remarks"));

                mapList.add(map);
            }

            DetailTableInfo dtsInfo = new DetailTableInfo();
            // DetailTable[] dts = new DetailTable[mapList.size()];
            DetailTable[] dts = new DetailTable[1];
            dts[0] = new DetailTable();
            dts[0].setId("1");
            Row[] rows = new Row[mapList.size()];
            for (int k = 0; k < mapList.size(); k++) {
                Map<String, Object> item = mapList.get(k);

                rows[k] = new Row();
                rows[k].setId(String.valueOf(k));
                Cell[] cl = { new Cell(), new Cell(), new Cell(), new Cell(), new Cell(), new Cell(), new Cell(),
                        new Cell(), new Cell() };
                int x = 0;
                for (Map.Entry<String, Object> entry : item.entrySet()) {
                    cl[x].setName(entry.getKey());
                    cl[x].setValue(entry.getValue() == null ? "" : entry.getValue().toString());
                    x++;
                }
                rows[k].setCell(cl);
            }
            dts[0].setRow(rows);
            dtsInfo.setDetailTable(dts);

            reqinfo.setMainTableInfo(wmi);
            reqinfo.setDetailTableInfo(dtsInfo);

            System.out.println("==========海外盘盈盘亏提交OA reqinfo==========\n" + JSON.toJSONString(reqinfo));

            // 生成待办 ，返回待办id
            int reqid = Integer.parseInt(wfproxy.createRequest(reqinfo));
            // 返回大于0 的数字则调用成功
            System.out.println("海外盘盈盘亏提交OA审批，返回 reqid:" + reqid);
            if (reqid > 0) {
                iOverseaOperateLogService.addOverseaOperateLog(spmsUser.getUserId(), overseaInvChkAc.getUuid(),
                        "海外盘盈盘亏提交OA成功", "Oversea InvChk submit OA Successed", oaLog, JSON.toJSONString(reqinfo),
                        String.valueOf(reqid), "");
            } else {
                iOverseaOperateLogService.addOverseaOperateLog(spmsUser.getUserId(), overseaInvChkAc.getUuid(),
                        "海外盘盈盘亏提交OA失败", "Oversea InvChk submit OA Failure", oaLog, JSON.toJSONString(reqinfo),
                        String.valueOf(reqid), "");
            }
            return reqid;
        } catch (RemoteException remoteException) {
            remoteException.printStackTrace();
            System.out.println("=========海外盘盈盘亏提交OA连接错误=========" + remoteException.getMessage());
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("========海外盘盈盘亏提交OA信息请求参数：" + overseaInvChkAc.toString() + "\n请求提交OA异常=========\n"
                    + e.getMessage());
            return 0;
        }
    }

    /** 获取海外仓盘盈盘亏任务，带明细不分页报表 */
    @Override
    public ResponseResult getOverseaInvCheckAction(OverseaInvCheckActionSearchDTO overseaInvCheckActionSearchDTO) {
        return ResponseResult.success().add("overseaInvCheckActionList", this.baseMapper.getOverseaInvCheckAction(overseaInvCheckActionSearchDTO));
    }
}
